#include <format>
#include <iostream>
#include <source_location>
#include <cstdint>

enum class log_level : std::uint8_t
{
    trace,
    debug,
    info,
    critical,
    warning,
    error,
    fatal
};
static log_level max_level;

std::string get_log_level_name(log_level level)
{

}


template <typename T>
struct with_source_location
{
private:
    T inner; // 用于存储被封装的对象
    std::source_location loc; // 用于存储源代码位置信息

public:
    // 构造函数，接受任意类型的参数，用来构造 inner 对象，并记录当前位置的源代码信息
    template <typename U> requires std::constructible_from<T, U>
    constexpr with_source_location(U&& inner, std::source_location location = std::source_location::current())
        : inner(std::forward<U>(inner)), loc(std::move(location)) {}
    // 为了确保源代码位置信息在编译时生成并嵌入到日志中，使用 consteval 是必须的。这确保了构造函数在编译时求值，从而使得 std::source_location::current()
    // 能够正确地在编译时返回源代码位置信息。如果使用 constexpr 或者不使用关键字，编译器无法在编译时生成这些信息，导致编译错误。

    // 返回被封装的对象
    constexpr T const& format() const { return inner; }
    // 返回源代码位置信息
    constexpr std::source_location const& location() const { return loc; }
};


template <typename... Args>
void generate_log(log_level level, with_source_location<std::format_string<Args...>> fmt, Args&&... args)
{
    if (level >  max_level)
    {
        auto const& loc = fmt.location();
        std::cout << loc.file_name() << ":" << loc.line() << " [" << get_log_level_name(level) << "] "
            << std::vformat(fmt.format().get(), std::make_format_args(args...)) << '\n';
    }
}

int main()
{
    generate_log(log_level::debug,"hello {}", "aquawius");
    return 0;
}
